import Foundation
import SwiftUI

struct AssociationKey { // 存储密钥
    static let accent = "BearCalendar.AssociationKey.accent"
    static let theme = "BearCalendar.AssociationKey.theme"
    static let showReminder = "BearCalendar.AssociationKey.showReminder"
    static let showEvent = "BearCalendar.AssociationKey.showEvent"
    static let showLunar = "BearCalendar.AssociationKey.showLunar"
    static let showFestival = "BearCalendar.AssociationKey.showFestival"
    static let language = "BearCalendar.AssociationKey.language"
    static let sync = "BearCalendar.AssociationKey.sync"
    /* 暂时无用 */
    static let festivalPush = "BearCalendar.AssociationKey.festivalPush"
    static let pushTime = "BearCalendar.AssociationKey.pushTime"
    static let pushSound = "BearCalendar.AssociationKey.pushSound"
    static let pushBadge = "BearCalendar.AssociationKey.pushBadge"
    /*******************/
    static let onlyShowCurrentMonth = "BearCalendar.AssociationKey.onlyShowCurrentMonth"
    static let firstWeek = "BearCalendar.AssociationKey.firstWeek"
    #if os(macOS)
    static let startAtLogin = "BearCalendar.AssociationKey.startAtLogin"
    static let showDockIcon = "BearCalendar.AssociationKey.showDockIcon"
    static let menuBar = "BearCalendar.AssociationKey.menuBar"
    static let compactMode = "BearCalendar.AssociationKey.compactMode"
    static let timeReminds = "BearCalendar.AssociationKey.timeReminds"
    static let movePopup = "BearCalendar.AssociationKey.movePopup"
    #endif
    // 颜色
    static let background = "BearCalendar.AssociationKey.background"
    static let normal = "BearCalendar.AssociationKey.normal"
    static let week = "BearCalendar.AssociationKey.week"
    static let festival = "BearCalendar.AssociationKey.festival"
    static let current = "BearCalendar.AssociationKey.current"
    static let calendar = "BearCalendar.AssociationKey.calendar"
    static let reminder = "BearCalendar.AssociationKey.reminder"
    static let work = "BearCalendar.AssociationKey.work"
    static let rest = "BearCalendar.AssociationKey.rest"
    static let recommends = "BearCalendar.AssociationKey.recommends"
    static let avoid = "BearCalendar.AssociationKey.avoid"
    static let taboo = "BearCalendar.AssociationKey.taboo"

    // 字体
    static let normalFont = "BearCalendar.AssociationKey.normalFont"
    static let tagFont = "BearCalendar.AssociationKey.tagFont"
    static let titleFont = "BearCalendar.AssociationKey.titleFont"
    static let subtitleFont = "BearCalendar.AssociationKey.subtitleFont"
    static let weekFont = "BearCalendar.AssociationKey.weekFont"
    static let dateFont = "BearCalendar.AssociationKey.dateFont"
    static let festivalFont = "BearCalendar.AssociationKey.festivalFont"

    static let isResetable = "BearCalendar.AssociationKey.isResetable"
}

// 模块内的bundle
var moduleBundle: Bundle {
    let language = Preference.shared.language
    var bundle: Bundle = .module
    if let path = Bundle.module.path(forResource: language.locale.identifier, ofType: "lproj") {
        bundle = Bundle(path: path) ?? .module
    }
    return bundle
}

// 检测当前运行主体是否是扩展程序
public var isRunningInExtension: Bool {
    return Bundle.main.bundlePath.hasSuffix(".appex")
}

// 判断深色模式
public var isDarkMode: Bool {
    #if os(macOS)
    return NSApplication.shared.effectiveAppearance.name == .darkAqua
    #elseif os(iOS)
    switch UITraitCollection.current.userInterfaceStyle {
    case .dark: return true
    default: return false
    }
    #else
    return false
    #endif
}


public enum Language: String {
    case cn
    case tr = "ct"
    case en
    case system

    public var locale: Locale {
        switch self {
        case .cn: Locale(identifier: "zh-Hans")
        case .tr: Locale(identifier: "zh-Hant")
        case .en: Locale(identifier: "en")
        case .system:
            switch Preference.language {
            case .tr: Locale(identifier: "zh-Hant")
            case .en: Locale(identifier: "en")
            default: Locale(identifier: "zh-Hans")
            }
        }
    }
    
    public var isEnglish: Bool {
        switch self {
        case .cn, .tr: false
        case .en: true
        case .system: Preference.language == .en
        }
    }
    
    public var title: String {
        return switch self {
        case .cn: NSLocalizedString("BearCalendar.language.cn", bundle: moduleBundle, comment: "")
        case .tr: NSLocalizedString("BearCalendar.language.tr", bundle: moduleBundle, comment: "")
        case .en: NSLocalizedString("BearCalendar.language.en", bundle: moduleBundle, comment: "")
        case .system: NSLocalizedString("BearCalendar.language.system", bundle: moduleBundle, comment: "")
        }
    }

    public static var current: Language {
        guard let languages = UserDefaults.standard.object(forKey: "AppleLanguages") as? [String], let current = languages.first else { return .en }
        if current.contains("zh-Hans") {
            return .cn
        } else if current.contains("zh-Hant") {
            return .tr
        } else {
            return .en
        }
    }
}

public enum Theme: Int, CaseIterable, RawRepresentable {
    case system = 0, light, dark
    
    public typealias RawValue = Int
    
    public init?(rawValue: Int) {
        if rawValue == 0 {
            self = .system
        } else if rawValue == 1 {
            self = .light
        } else {
            self = .dark
        }
    }
    
    public var rawValue: Int {
        switch self {
        case .system: 0
        case .light: 1
        case .dark: 2
        }
    }
    
    public var title: String {
        return switch self {
        case .system: NSLocalizedString("BearCalendar.theme.system", bundle: moduleBundle, comment: "")
        case .light: NSLocalizedString("BearCalendar.theme.light", bundle: moduleBundle, comment: "")
        case .dark: NSLocalizedString("BearCalendar.theme.dark", bundle: moduleBundle, comment: "")
        }
    }
    
    public var colorScheme: ColorScheme {
        switch self {
        case .system: isDarkMode ? .dark : .light
        case .light: .light
        case .dark: .dark
        }
    }
}

public extension Theme {
    var tintColor: Color {
        switch self {
        case .system: Color("tint", bundle: .module)
        case .light: .black
        case .dark: .white
        }
    }
    
    var cellColor: Color {
        switch self {
        case .system: Color("cell", bundle: .module)
        case .light: .white
        case .dark: Color(hex: "#1D1D24")
        }
    }
    
    var dividerColor: Color {
        switch self {
        case .system: Color("divider", bundle: .module)
        case .light: Color(hex: "F5F7F8")
        case .dark: Color(hex: "323232")
        }
    }
    
    var headerColor: Color {
        switch self {
        case .system: Color("header", bundle: .module)
        case .light: Color(hex: "626162")
        case .dark: Color(hex: "BBBBBB")
        }
    }
    
    #if os(macOS)
    var segmentedColor: Color {
        switch self {
        case .system: Color("segmented", bundle: .module)
        case .light: Color(hex: "EEEEEF")
        case .dark: Color(hex: "21232E")
        }
    }
    #endif
    
    var background: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.background.dark : Preference.shared.background.light
        case .light: Preference.shared.background.light
        case .dark: Preference.shared.background.dark
        }
    }
    
    var accent: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.accent.dark : Preference.shared.accent.light
        case .light: Preference.shared.accent.light
        case .dark: Preference.shared.accent.dark
        }
    }
    
    var normal: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.normal.dark : Preference.shared.normal.light
        case .light: Preference.shared.normal.light
        case .dark: Preference.shared.normal.dark
        }
    }
    
    var week: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.week.dark : Preference.shared.week.light
        case .light: Preference.shared.week.light
        case .dark: Preference.shared.week.dark
        }
    }
    
    var festival: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.festival.dark : Preference.shared.festival.light
        case .light: Preference.shared.festival.light
        case .dark: Preference.shared.festival.dark
        }
    }
    
    var current: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.current.dark : Preference.shared.current.light
        case .light: Preference.shared.current.light
        case .dark: Preference.shared.current.dark
        }
    }
    
    var calendar: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.calendar.dark : Preference.shared.calendar.light
        case .light: Preference.shared.calendar.light
        case .dark: Preference.shared.calendar.dark
        }
    }
    
    var reminder: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.reminder.dark : Preference.shared.reminder.light
        case .light: Preference.shared.reminder.light
        case .dark: Preference.shared.reminder.dark
        }
    }
    
    var work: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.work.dark : Preference.shared.work.light
        case .light: Preference.shared.work.light
        case .dark: Preference.shared.work.dark
        }
    }
    
    var rest: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.rest.dark : Preference.shared.rest.light
        case .light: Preference.shared.rest.light
        case .dark: Preference.shared.rest.dark
        }
    }
    
    var toboo: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.taboo.dark : Preference.shared.taboo.light
        case .light: Preference.shared.taboo.light
        case .dark: Preference.shared.taboo.dark
        }
    }
    
    var avoid: Color {
        switch self {
        case .system: isDarkMode ? Preference.shared.avoid.dark : Preference.shared.avoid.light
        case .light: Preference.shared.avoid.light
        case .dark: Preference.shared.avoid.dark
        }
    }
}

#if os(macOS)
public enum MenubarStyle: RawRepresentable, Hashable {
    public init?(rawValue: String) {
        if rawValue.hasPrefix("dateTime{_}") {
            var style: MenubarStyle.DateStyle = [.date, .time, .time24]
            guard let value = Int(rawValue.replacingOccurrences(of: "dateTime{_}", with: "")) else {
                self = .dateTime(style)
                return
            }
            style = MenubarStyle.DateStyle(rawValue: value)
            self = .dateTime(style)
        } else if rawValue.hasPrefix("icon{_}") {
            let value = Int(rawValue.replacingOccurrences(of: "icon{_}", with: "")) ?? 0
            let style = IconStyle(rawValue: value) ?? .logo
            self = .icon(style)
        } else {
            self = .icon(.logo)
        }
    }
    
    public var rawValue: String {
        switch self {
        case .icon(let style):
            return "icon{_}\(style.rawValue)"
        case .dateTime(let style):
            return "dateTime{_}" + "\(style.rawValue)"
        }
    }
    
    public typealias RawValue = String
    
    public enum IconStyle: Int {
        case logo = 0
        case day
    }
    
    public struct DateStyle: OptionSet {
        public var rawValue: Int
        public static let date = DateStyle(rawValue: 1 << 0)
        public static let week = DateStyle(rawValue: 1 << 1)
        public static let apm = DateStyle(rawValue: 1 << 2)
        public static let time = DateStyle(rawValue: 1 << 3)
        public static let time24 = DateStyle(rawValue: 1 << 4)
        public static let second = DateStyle(rawValue: 1 << 5)
        public static let year = DateStyle(rawValue: 1 << 6)
        
        public init(rawValue: Int) {
            self.rawValue = rawValue
        }
        
        public var dateText: String {
            var format = ""
            if contains(.week) {
                format += "E"
            }
            if contains(.apm) {
                format = format.isEmpty ? "a" : format + "a"
            }
            if contains(.date) {
                if Preference.language == .en {
                    let df = contains(.year) ? "yyyy/M/d" : "MMMM/d"
                    format = format.isEmpty ? "yyyy/M/d" : (format + " " + df)
                } else {
                    let year = NSLocalizedString("BearCalendar.calendar.year", bundle: moduleBundle, comment: "")
                    let month = NSLocalizedString("BearCalendar.calendar.month", bundle: moduleBundle, comment: "")
                    let day = NSLocalizedString("BearCalendar.calendar.day", bundle: moduleBundle, comment: "")
                    let df = contains(.year) ? "yyyy\(year)M\(month)d\(day)" : "M\(month)d\(day)"
                    format = format.isEmpty ? df : (format + " " + df)
                }
            }
            if contains(.time) {
                if contains(.time24) {
                    format = format.isEmpty ? "HH:mm" : format + " HH:mm"
                } else {
                    format = format.isEmpty ? "hh:mm" : format + " hh:mm"
                }
            }
            if contains(.second) {
                format += ":ss"
            }
            let dateFormatter = DateFormatter()
            dateFormatter.locale = Preference.language.locale
            dateFormatter.dateFormat = format
            return dateFormatter.string(from: Date())
        }
        
        public var compactAttributedDate: NSAttributedString {
            return dateAttributedString(true)
        }
        
        public var attributedDate: NSAttributedString {
            return dateAttributedString(false)
        }
        
        public var attributedTime: NSAttributedString {
            var format = ""
            if contains(.time) {
                if contains(.time24) {
                    format = "HH:mm"
                } else {
                    format = "hh:mm"
                }
            }
            if contains(.second) {
                format += ":ss"
            }
            let dateFormatter = DateFormatter()
            dateFormatter.locale = Preference.language.locale
            dateFormatter.dateFormat = format
            let timeString = dateFormatter.string(from: Date())
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineBreakMode = .byWordWrapping
            paragraphStyle.alignment = .center
            let titleAttributes: [NSAttributedString.Key: Any] = [
                .font: NSFont.monospacedDigitSystemFont(ofSize: 12, weight: .regular),
                .paragraphStyle: paragraphStyle
            ]
            return NSAttributedString(string: timeString, attributes: titleAttributes)
        }
        
        public var dateSize: CGSize {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineBreakMode = .byWordWrapping
            paragraphStyle.alignment = .center
            let space = NSAttributedString(string: " ", attributes: [
                .font: NSFont.monospacedDigitSystemFont(ofSize: 12, weight: .regular),
                .paragraphStyle: paragraphStyle
            ])
            let attributedString: NSMutableAttributedString = NSMutableAttributedString(attributedString: attributedDate)
            attributedString.append(space)
            attributedString.append(attributedTime)
            return attributedString.boundingRect(with: NSSize(width: CGFloat.greatestFiniteMagnitude, height: 24), options: [.usesLineFragmentOrigin, .usesFontLeading], context: NSStringDrawingContext()).size
        }
        
        func dateAttributedString(_ isCompactMode: Bool = false) -> NSAttributedString {
            var format = ""
            var fontSize: CGFloat = 0
            if contains(.week) {
                format += "E"
                fontSize = 12
            }
            if contains(.apm) {
                format = format.isEmpty ? "a" : format + " a"
                fontSize = 12
            }
            if contains(.date) {
                fontSize = format.isEmpty ? 12 : 8
                let sep = isCompactMode ? "\n" : " "
                if Preference.language == .en {
                    let df = contains(.year) ? "yyyy/M/d" : "MMM/d"
                    format = format.isEmpty ? "yyyy/M/d" : (format + sep + df)
                } else {
                    let year = NSLocalizedString("BearCalendar.calendar.year", bundle: moduleBundle, comment: "")
                    let month = NSLocalizedString("BearCalendar.calendar.month", bundle: moduleBundle, comment: "")
                    let day = NSLocalizedString("BearCalendar.calendar.day", bundle: moduleBundle, comment: "")
                    let df = contains(.year) ? "yyyy\(year)M\(month)d\(day)" : "M\(month)d\(day)"
                    format = format.isEmpty ? df : (format + sep + df)
                }
            }
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineBreakMode = .byWordWrapping
            paragraphStyle.alignment = .center
            fontSize = isCompactMode ? fontSize : 12
            let titleAttributes: [NSAttributedString.Key: Any] = [
                .font: NSFont.monospacedDigitSystemFont(ofSize: fontSize, weight: .regular),
                .paragraphStyle: paragraphStyle
            ]
            let dateFormatter = DateFormatter()
            dateFormatter.locale = Preference.language.locale
            dateFormatter.dateFormat = format
            let dateSting = dateFormatter.string(from: Date())
            return NSAttributedString(string: dateSting, attributes: titleAttributes)
        }
    }
    
    case icon(IconStyle)
    case dateTime(DateStyle)
    
    public var title: String {
        switch self {
        case .icon(_): return NSLocalizedString("BearCalendar.menubar.icon", bundle: moduleBundle, comment: "")
        case .dateTime(_): return NSLocalizedString("BearCalendar.menubar.date", bundle: moduleBundle, comment: "")
        }
    }
}
#endif
